﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace AmiEmuLib.Native
{
    /// <summary>
    /// Native things.
    /// </summary>
    public static class NativeRawInput
    {
        /// <summary>
        /// WM_INPUT, wParam, Input occurred while the application was in the foreground. 
        /// </summary>
        public static readonly IntPtr RIM_INPUT = (IntPtr)0;

        /// <summary>
        /// WM_INPUT, wParam, Input occurred while the application was not in the foreground. 
        /// </summary>
        public static readonly IntPtr RIM_INPUTSINK = (IntPtr)1;

        public const short KEYBOARD_OVERRUN_MAKE_CODE = 0xFF;

        /// <summary>
        /// Enumeration containing flags for a raw input device.
        /// </summary>
        [Flags()]
        public enum RawInputDeviceFlags
        {
            /// <summary>No flags.</summary>
            None = 0,
            /// <summary>
            /// If set, this removes the top level collection from the inclusion list. 
            /// This tells the operating system to stop reading from a device which matches the 
            /// top level collection.
            /// </summary>
            Remove = 0x00000001,
            /// <summary>
            /// If set, this specifies the top level collections to exclude when reading 
            /// a complete usage page. This flag only affects a TLC whose usage page is already 
            /// specified with PageOnly.
            /// </summary>
            Exclude = 0x00000010,
            /// <summary>
            /// If set, this specifies all devices whose top level collection is from the 
            /// specified usUsagePage. Note that Usage must be zero. To exclude a particular top 
            /// level collection, use Exclude.
            /// </summary>
            PageOnly = 0x00000020,
            /// <summary>
            /// If set, this prevents any devices specified by UsagePage or Usage from 
            /// generating legacy messages. This is only for the mouse and keyboard.
            /// </summary>
            NoLegacy = 0x00000030,
            /// <summary>
            /// If set, this enables the caller to receive the input even when the caller 
            /// is not in the foreground. Note that WindowHandle must be specified.
            /// </summary>
            InputSink = 0x00000100,
            /// <summary>
            /// If set, the mouse button click does not activate the other window.
            /// </summary>
            CaptureMouse = 0x00000200,
            /// <summary>
            /// If set, the application-defined keyboard device hotkeys are not handled. 
            /// However, the system hotkeys; for example, ALT+TAB and CTRL+ALT+DEL, are still 
            /// handled. By default, all keyboard hotkeys are handled. NoHotKeys can be 
            /// specified even if NoLegacy is not specified and WindowHandle is NULL.
            /// </summary>
            NoHotKeys = 0x00000200,
            /// <summary>
            /// If set, application keys are handled.  NoLegacy must be specified. 
            /// Keyboard only.
            /// </summary>
            AppKeys = 0x00000400,
            /// <summary>
            /// If set, this enables the caller to receive WM_INPUT_DEVICE_CHANGE notifications 
            /// for device arrival and device removal.
            /// Windows XP:  This flag is not supported until Windows Vista
            /// </summary>
            DeviceNotify = 0x00002000
        }

        /// <summary>
        /// Value type for raw input devices.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct RawInputDevice
        {
            public static readonly uint StructSize = (uint)Marshal.SizeOf(typeof(RawInputDevice));

            /// <summary>
            /// Top level collection Usage page for the raw input device.
            /// </summary>
            public ushort UsagePage;
            /// <summary>
            /// Top level collection Usage for the raw input device. 
            /// </summary>
            public ushort Usage;
            /// <summary>
            /// Mode flag that specifies how to interpret the information provided by UsagePage 
            /// and Usage.
            /// </summary>
            public RawInputDeviceFlags Flags;
            /// <summary>
            /// Handle to the target device. If NULL, it follows the keyboard focus.
            /// </summary>
            public IntPtr WindowHandle;
        }

        /// <summary>Function to register a raw input device.</summary>
        /// <param name="pRawInputDevices">
        /// Array of raw input devices.
        /// </param>
        /// <param name="uiNumDevices">
        /// Number of devices.
        /// </param>
        /// <param name="cbSize">
        /// Size of the RAWINPUTDEVICE structure.
        /// </param>
        /// <returns>
        /// TRUE if successful, FALSE if not.
        /// </returns>
        [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool RegisterRawInputDevices
        (
            RawInputDevice[] RawInputDevices,
            uint NumDevices,
            uint Size
        );


        /// <summary>
        /// The type of device. 
        /// </summary>
        public enum RawInputDeviceType : uint
        {
            /// <summary>
            /// The device is a mouse.
            /// </summary>
            MOUSE = 0,
            /// <summary>
            /// The device is a keyboard.
            /// </summary>
            KEYBOARD = 1,
            /// <summary>
            /// The device is an HID that is not a keyboard and not a mouse.
            /// </summary>
            HID = 2
        }

        /// <summary>
        /// Contains information about a raw input device.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct RawInputDeviceList
        {
            public static readonly uint StructSize = (uint)Marshal.SizeOf(typeof(RawInputDeviceList));

            /// <summary>
            /// A handle to the raw input device. 
            /// </summary>
            public IntPtr hDevice;
            /// <summary>
            /// The type of device. 
            /// </summary>
            public RawInputDeviceType Type;
        }

        /// <summary>
        /// Enumerates the raw input devices attached to the system. 
        /// </summary>
        /// <param name="RawInputDeviceList">
        /// An array of RAWINPUTDEVICELIST structures for the devices attached to the system. 
        /// If NULL, the number of devices are returned in *puiNumDevices. </param>
        /// <param name="NumDevices">
        /// If pRawInputDeviceList is NULL, the function populates this variable with the number of 
        /// devices attached to the system; otherwise, this variable specifies the number of 
        /// RAWINPUTDEVICELIST structures that can be contained in the buffer to which 
        /// pRawInputDeviceList points. If this value is less than the number of devices 
        /// attached to the system, the function returns the actual number of devices in 
        /// this variable and fails with ERROR_INSUFFICIENT_BUFFER.
        /// </param>
        /// <param name="Size">
        /// The size of a RAWINPUTDEVICELIST structure, in bytes.
        /// </param>
        /// <returns>If the function is successful, the return value is the number of devices stored 
        /// in the buffer pointed to by pRawInputDeviceList. On any other error, the function 
        /// returns (UINT) -1 and GetLastError returns the error indication.
        /// </returns>
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern uint GetRawInputDeviceList
        (
            [In, Out] RawInputDeviceList[] RawInputDeviceList,
            ref uint NumDevices,
            uint Size /* = RawInputDeviceList.StructSize */
        );

        public enum RawInputDeviceInfoCommand : uint
        {
            DEVICENAME = 0x20000007,
            DEVICEINFO = 0x2000000B,
            PREPARSEDDATA = 0x20000005
        }

        /// <summary>
        /// Defines the raw input data coming from the specified mouse.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct RawInfoMouseInfo
        {
            /// <summary>
            /// The identifier of the mouse device.
            /// </summary>
            public int Id;
            /// <summary>
            /// The number of buttons for the mouse.
            /// </summary>
            public int NumberOfButtons;
            /// <summary>
            /// The number of data points per second. This information may not be applicable 
            /// for every mouse device.
            /// </summary>
            public int SampleRate;
            /// <summary>
            /// TRUE if the mouse has a wheel for horizontal scrolling; otherwise, FALSE. 
            /// Windows XP:  This member is only supported starting with Windows Vista.
            /// </summary>
            [MarshalAs(UnmanagedType.Bool)]
            public bool HasHorizontalWheel;
        }

        /// <summary>
        /// Defines the raw input data coming from the specified keyboard. 
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct RawInfoKeyboardInfo
        {
            /// <summary>
            /// The type of the keyboard. 
            /// </summary>
            public int Type;
            /// <summary>
            /// The subtype of the keyboard. 
            /// </summary>
            public int SubType;
            /// <summary>
            /// The scan code mode. 
            /// </summary>
            public int KeyboardMode;
            /// <summary>
            /// The number of function keys on the keyboard.
            /// </summary>
            public int NumberOfFunctionKeys;
            /// <summary>
            /// The number of LED indicators on the keyboard.
            /// </summary>
            public int NumberOfIndicators;
            /// <summary>
            /// The total number of keys on the keyboard. 
            /// </summary>
            public int NumberOfKeysTotal;
        }

        /// <summary>
        /// Defines the raw input data coming from the specified Human Interface Device (HID). 
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct RawInfoHIDInfo
        {
            /// <summary>
            /// The vendor identifier for the HID. 
            /// </summary>
            public int VendorId;
            /// <summary>
            /// The product identifier for the HID. 
            /// </summary>
            public int ProductId;
            /// <summary>
            /// The version number for the HID. 
            /// </summary>
            public int VersionNumber;
            /// <summary>
            /// The top-level collection Usage Page for the device. 
            /// </summary>
            public ushort UsagePage;
            /// <summary>
            /// The top-level collection Usage for the device. 
            /// </summary>
            public ushort Usage;
        }

        /// <summary>
        /// Defines the raw input data coming from any device. 
        /// </summary>
        [StructLayout(LayoutKind.Explicit)]
        public struct RawInputDeviceInfo
        {
            public static readonly uint StructSize = (uint)Marshal.SizeOf(typeof(RawInputDeviceInfo));

            /// <summary>
            /// The size, in bytes, of the RawInfoDeviceInfo structure. 
            /// </summary>
            [FieldOffset(0)]
            public int Size;
            /// <summary>
            /// The type of raw input data.
            /// </summary>
            [FieldOffset(4)]
            public RawInputDeviceType Type;
            /// <summary>
            /// If dwType is RawInputDeviceType.MOUSE, this is the RawInfoMouseInfo structure 
            /// that defines the mouse. 
            [FieldOffset(8)]
            public RawInfoMouseInfo Mouse;
            /// If dwType is RawInputDeviceType.KEYBOARD, this is the RawInfoKeyboardInfo structure 
            /// that defines the keyboard. 
            [FieldOffset(8)]
            public RawInfoKeyboardInfo Keyboard;
            /// If dwType is RawInputDeviceType.HID, this is the RawInfoHIDInfo structure 
            /// that defines the HID device. 
            /// </summary>
            [FieldOffset(8)]
            public RawInfoHIDInfo HID;
        }

        /// <summary>
        /// Retrieves information about the raw input device name size in chars.
        /// </summary>
        /// <param name="hDevice">
        /// A handle to the raw input device. This comes from the lParam of the WM_INPUT message, 
        /// from the hDevice member of RAWINPUTHEADER, or from GetRawInputDeviceList. 
        /// It can also be NULL if an application inserts input data, for example, by using SendInput. 
        /// </param>
        /// <param name="Command">
        /// Should be set to RawInputDeviceInfoCommand.DEVICENAME. 
        /// </param>
        /// <param name="Null">
        /// Should be set to IntPtr.Zero (null).
        /// </param>
        /// <param name="Size">
        /// Will return the character count (not the byte count).
        /// </param>
        /// <returns>
        /// If successful, this function returns a non-negative number indicating the number of 
        /// bytes copied to pData. If pData is not large enough for the data, the function returns -1. 
        /// If pData is NULL, the function returns a value of zero. In both of these cases, 
        /// pcbSize is set to the minimum size required for the pData buffer. 
        /// Call GetLastError to identify any other errors.
        /// </returns>
        [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public extern static uint GetRawInputDeviceInfo
        (
            IntPtr hDevice,
            RawInputDeviceInfoCommand Command /* = RawInputDeviceInfoCommand.DEVICENAME */,
            IntPtr Null /* = IntPtr.Zero */,
            ref uint Size
        );

        /// <summary>
        /// Retrieves information about the raw input device info.
        /// </summary>
        /// <param name="hDevice">
        /// A handle to the raw input device. This comes from the lParam of the WM_INPUT message, 
        /// from the hDevice member of RAWINPUTHEADER, or from GetRawInputDeviceList. 
        /// It can also be NULL if an application inserts input data, for example, by using SendInput. 
        /// </param>
        /// <param name="Command">
        /// Should be set to RawInputDeviceInfoCommand.DEVICEINFO. 
        /// </param>
        /// <param name="DeviceInfo">
        /// Device info.
        /// </param>
        /// <param name="Size">
        /// The size, in bytes of RID_DEVICE_INFO. 
        /// </param>
        /// <returns>
        /// If successful, this function returns a non-negative number indicating the number of 
        /// bytes copied to pData. If pData is not large enough for the data, the function returns -1. 
        /// If pData is NULL, the function returns a value of zero. In both of these cases, 
        /// pcbSize is set to the minimum size required for the pData buffer. 
        /// Call GetLastError to identify any other errors.
        /// </returns>
        [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public extern static uint GetRawInputDeviceInfo
        (
            IntPtr hDevice,
            RawInputDeviceInfoCommand Command /* = RawInputDeviceInfoCommand.DEVICEINFO */,
            ref RawInputDeviceInfo DeviceInfo,
            ref uint Size /* = RawInputDeviceInfo.StructSize */
        );

        /// <summary>
        /// Retrieves information about the raw input device name.
        /// </summary>
        /// <param name="hDevice">
        /// A handle to the raw input device. This comes from the lParam of the WM_INPUT message, 
        /// from the hDevice member of RAWINPUTHEADER, or from GetRawInputDeviceList. 
        /// It can also be NULL if an application inserts input data, for example, by using SendInput. 
        /// </param>
        /// <param name="Command">
        /// Should be set to RawInputDeviceInfoCommand.DEVICENAME. 
        /// </param>
        /// <param name="DeviceName">
        /// StringBuilder should be Device Info length.
        /// </param>
        /// <param name="Size"></param>
        /// Should be Device Info length.
        /// <returns>
        /// If successful, this function returns a non-negative number indicating the number of 
        /// bytes copied to pData. If pData is not large enough for the data, the function returns -1. 
        /// If pData is NULL, the function returns a value of zero. In both of these cases, 
        /// pcbSize is set to the minimum size required for the pData buffer. 
        /// Call GetLastError to identify any other errors.
        /// </returns>
        [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public extern static uint GetRawInputDeviceInfo
        (
            IntPtr hDevice,
            RawInputDeviceInfoCommand Command /* = RawInputDeviceInfoCommand.DEVICENAME */,
            StringBuilder DeviceName,
            ref uint Size
        );

        /// <summary>
        /// Enumeration contanining the command types to issue for GetRawInputData().
        /// </summary>
        public enum RawInputCommand : uint
        {
            /// <summary>
            /// Get input data.
            /// </summary>
            Input = 0x10000003,
            /// <summary>
            /// Get header data.
            /// </summary>
            Header = 0x10000005
        }

        /// <summary>
        /// Contains the header information that is part of the raw input data. 
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct RawInputHeader
        {
            public static readonly uint StructSize =
                (uint)Marshal.SizeOf(typeof(RawInputHeader));

            /// <summary>
            /// Type of device the input is coming from.
            /// </summary>
            public RawInputDeviceType Type;
            /// <summary>
            /// The size, in bytes, of the entire input packet of data. 
            /// This includes RAWINPUT plus possible extra input reports in the RAWHID 
            /// variable length array. 
            /// </summary>
            public int Size;
            /// <summary>
            /// A handle to the device generating the raw input data. 
            /// </summary>
            public IntPtr hDevice;
            /// <summary>
            /// The value passed in the wParam parameter of the WM_INPUT message. 
            /// </summary>
            public IntPtr wParam;
        }

        /// <summary>
        /// Enumeration containing the flags for raw mouse data.
        /// </summary>
        [Flags]
        public enum RawMouseFlags : ushort
        {
            /// <summary>
            /// Mouse movement data is relative to the last mouse position.
            /// </summary>
            MoveRelative = 0,
            /// <summary>
            /// Mouse movement data is based on absolute position.
            /// </summary>
            MoveAbsolute = 1,
            /// <summary>
            /// Mouse coordinates are mapped to the virtual desktop (for a multiple monitor system).
            /// </summary>
            VirtualDesktop = 2,
            /// <summary>
            /// Mouse attributes changed; application needs to query the mouse attributes.
            /// </summary>
            AttributesChanged = 4
        }

        /// <summary>
        /// Enumeration containing the button data for raw mouse input.
        /// </summary>
        [Flags]
        public enum RawMouseButtons : ushort
        {
            /// <summary>
            /// No button.
            /// </summary>
            None = 0,
            /// <summary>
            /// Left (button 1) down.
            /// </summary>
            LeftDown = 0x0001,
            /// <summary>
            /// Left (button 1) up.
            /// </summary>
            LeftUp = 0x0002,
            /// <summary>
            /// Right (button 2) down.
            /// </summary>
            RightDown = 0x0004,
            /// <summary>
            /// Right (button 2) up.
            /// </summary>
            RightUp = 0x0008,
            /// <summary>
            /// Middle (button 3) down.
            /// </summary>
            MiddleDown = 0x0010,
            /// <summary>
            /// Middle (button 3) up.
            /// </summary>
            MiddleUp = 0x0020,
            /// <summary>
            /// Button 4 down.
            /// </summary>
            Button4Down = 0x0040,
            /// <summary>
            /// Button 4 up.
            /// </summary>
            Button4Up = 0x0080,
            /// <summary>
            /// Button 5 down.
            /// </summary>
            Button5Down = 0x0100,
            /// <summary>
            /// Button 5 up.
            /// </summary>
            Button5Up = 0x0200,
            /// <summary>
            /// Mouse wheel moved.
            /// </summary>
            MouseWheel = 0x0400,
            /// <summary>
            /// Unofficial. Mouse horizontal wheel moved.
            /// </summary>
            MouseHorzWheel = 0x0800
        }

        /// <summary>
        /// Contains information about the state of the mouse.
        /// </summary>
        [StructLayout(LayoutKind.Explicit)]
        public struct RawMouse
        {
            /// <summary>
            /// The mouse state.
            /// </summary>
            [FieldOffset(0)]
            public RawMouseFlags Flags;
            /// <summary>
            /// Flags for the event.
            /// </summary>
            [FieldOffset(4)]
            public RawMouseButtons ButtonFlags;
            /// <summary>
            /// If the mouse wheel is moved, this will contain the delta amount.
            /// </summary>
            [FieldOffset(6)]
            public ushort ButtonData;
            /// <summary>
            /// Raw button data.
            /// </summary>
            [FieldOffset(8)]
            public uint RawButtons;
            /// <summary>
            /// The motion in the X direction. This is signed relative motion or 
            /// absolute motion, depending on the value of usFlags. 
            /// </summary>
            [FieldOffset(12)]
            public int LastX;
            /// <summary>
            /// The motion in the Y direction. This is signed relative motion or absolute motion, 
            /// depending on the value of usFlags. 
            /// </summary>
            [FieldOffset(16)]
            public int LastY;
            /// <summary>
            /// The device-specific additional information for the event. 
            /// </summary>
            [FieldOffset(20)]
            public uint ExtraInformation;
        }

        /// <summary>
        /// Enumeration containing flags for raw keyboard input.
        /// </summary>
        [Flags]
        public enum RawKeyboardFlags : ushort
        {
            /// <summary>
            /// The key is down.
            /// </summary>
            KeyMake = 0,
            /// <summary>
            /// The key is up.
            /// </summary>
            KeyBreak = 1,
            /// <summary>
            /// This is the left version of the key.
            /// </summary>
            KeyE0 = 2,
            /// <summary>
            /// This is the right version of the key.
            /// </summary>
            KeyE1 = 4,
            /// <summary>
            /// </summary>
            TerminalServerSetLED = 8,
            /// <summary></summary>
            TerminalServerShadow = 16,
            /// <summary></summary>
            TerminalServerVKPACKET = 32
        }

        /// <summary>
        /// Contains information about the state of the keyboard. 
        /// </summary>    
        [StructLayout(LayoutKind.Sequential)]
        public struct RawKeyboard
        {
            /// <summary>
            /// The scan code from the key depression. The scan code for keyboard overrun 
            /// is KEYBOARD_OVERRUN_MAKE_CODE. 
            /// </summary>
            public short MakeCode;
            /// <summary>
            /// Scan code information.
            /// </summary>
            public RawKeyboardFlags Flags;
            /// <summary>
            /// Reserved.
            /// </summary>
            public short Reserved;
            /// <summary>
            /// Virtual key code.
            /// </summary>
            public ushort VirtualKey;
            /// <summary>
            /// Corresponding window message.
            /// </summary>
            public uint Message;
            /// <summary>
            /// The device-specific additional information for the event. 
            /// </summary>
            public int ExtraInformation;
        }

        /// <summary>
        /// Value type for raw input from a HID.
        /// </summary>    
        [StructLayout(LayoutKind.Sequential)]
        public struct RawHID
        {
            /// <summary>
            /// Size of the HID data in bytes.
            /// </summary>
            public int Size;
            /// <summary>
            /// Number of HID in Data.
            /// </summary>
            public int Count;
            /// <summary>
            /// Data for the HID.
            /// </summary>
            public IntPtr Data;
        }

        /// <summary>
        /// Contains the raw input from a device. 
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct RawInput
        {
            public static readonly uint StructSize =
                (uint)Marshal.SizeOf(typeof(RawInput));

            /// <summary>
            /// Header for the data.
            /// </summary>
            public RawInputHeader Header;
            public Union Data;
            [StructLayout(LayoutKind.Explicit)]
            public struct Union
            {
                /// <summary>
                /// Mouse raw input data.
                /// </summary>
                [FieldOffset(0)]
                public RawMouse Mouse;
                /// <summary>
                /// Keyboard raw input data.
                /// </summary>
                [FieldOffset(0)]
                public RawKeyboard Keyboard;
                /// <summary>
                /// HID raw input data.
                /// </summary>
                [FieldOffset(0)]
                public RawHID HID;
            }
        }

        /// <summary>
        /// Retrieves the raw input from the specified device.
        /// </summary>
        /// <param name="hRawInput">
        /// A handle to the RAWINPUT structure. This comes from the lParam in WM_INPUT. 
        /// </param>
        /// <param name="Command">
        /// The command flag. 
        /// </param>
        /// <param name="RawInput">
        /// A pointer to the data that comes from the RAWINPUT structure. 
        /// This depends on the value of uiCommand. 
        /// If pData is NULL, the required size of the buffer is returned in *pcbSize. 
        /// </param>
        /// <param name="Size">
        /// The size, in bytes, of the data in pData. 
        /// If pData is NULL, the required size of the buffer is returned in *pcbSize. 
        /// </param>
        /// <param name="SizeHeader">
        /// The size, in bytes, of the RAWINPUTHEADER structure. 
        /// </param>
        /// <returns>
        /// If pData is NULL and the function is successful, the return value is 0. 
        /// If pData is not NULL and the function is successful, the return value is the 
        /// number of bytes copied into pData. If there is an error, the return value is (UINT)-1.
        /// </returns>
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern uint GetRawInputData
        (
            IntPtr hRawInput,
            RawInputCommand Command,
            out RawInput RawInput,
            ref uint Size,
            uint cbSizeHeader
        );

        /// <summary>
        /// The translation to be performed.
        /// </summary>
        public enum MapVirtualKeyEnum
        {
            /// <summary>
            /// uCode is a virtual-key code and is translated into a scan code. If it is a 
            /// virtual-key code that does not distinguish between left- and right-hand keys, 
            /// the left-hand scan code is returned. If there is no translation, the function 
            /// returns 0.
            /// </summary>
            MAPVK_VK_TO_VSC = 0x00,
            /// <summary>
            /// uCode is a scan code and is translated into a virtual-key code that does not 
            /// distinguish between left- and right-hand keys. If there is no translation, the 
            /// function returns 0.
            /// </summary>
            MAPVK_VSC_TO_VK = 0x01,
            /// <summary>
            /// uCode is a virtual-key code and is translated into an unshifted character 
            /// value in the low-order word of the return value. Dead keys (diacritics) are 
            /// indicated by setting the top bit of the return value. If there is no translation, 
            /// the function returns 0.
            /// </summary>
            MAPVK_VK_TO_CHAR = 0x02,
            /// <summary>
            /// uCode is a scan code and is translated into a virtual-key code that distinguishes 
            /// between left- and right-hand keys. If there is no translation, the function 
            /// returns 0.
            /// </summary>
            MAPVK_VSC_TO_VK_EX = 0x03,
            /// <summary>
            /// Vista only.
            /// </summary>
            MAPVK_VK_TO_VSC_EX = 0x04
        }

        /// <summary>
        /// Translates (maps) a virtual-key code into a scan code or character value, or 
        /// translates a scan code into a virtual-key code. To specify a handle to the keyboard 
        /// layout to use for translating the specified code, use the MapVirtualKeyEx function.
        /// </summary>
        /// <param name="Code">
        /// The virtual key code or scan code for a key. How this value is interpreted depends 
        /// on the value of the uMapType parameter. 
        /// </param>
        /// <param name="MapType">
        /// The translation to be performed. 
        /// </param>
        /// <returns>
        /// The return value is either a scan code, a virtual-key code, or a character value, 
        /// depending on the value of uCode and uMapType. If there is no translation, the return 
        /// value is zero.
        /// </returns>
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern uint MapVirtualKey
        (
            uint Code,
            MapVirtualKeyEnum MapType
        );

        /// <summary>
        /// Translates (maps) a virtual-key code into a scan code or character value, or 
        /// translates a scan code into a virtual-key code. The function translates the 
        /// codes using the input language and an input locale identifier.
        /// </summary>
        /// <param name="uCode">
        /// The virtual-key code or scan code for a key. How this value is interpreted depends 
        /// on the value of the uMapType parameter. Starting with Windows Vista, the high 
        /// byte of the uCode value can contain either 0xe0 or 0xe1 to specify the 
        /// extended scan code.
        /// </param>
        /// <param name="uMapType">
        /// The translation to perform.
        /// </param>
        /// <param name="dwhkl">
        /// Input locale identifier to use for translating the specified code. 
        /// This parameter can be any input locale identifier previously returned by the 
        /// LoadKeyboardLayout function. 
        /// </param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern uint MapVirtualKeyEx
        (
            uint Code,
            MapVirtualKeyEnum MapType,
            IntPtr hkl
        );

        /// <summary>
        /// Retrieves the active input locale identifier (formerly called the keyboard layout) 
        /// for the specified thread. If the idThread parameter is zero, the input locale 
        /// identifier for the active thread is returned.
        /// </summary>
        /// <param name="idThread">
        /// The identifier of the thread to query, or 0 for the current thread. 
        /// </param>
        /// <returns></returns>
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr GetKeyboardLayout
        (
            uint idThread
        );

        /// <summary>
        /// The event type contained in the union field
        /// </summary>
        public enum SendInputEventType : int
        {
            /// <summary>
            /// Contains Mouse event data
            /// </summary>
            InputMouse,
            /// <summary>
            /// Contains Keyboard event data
            /// </summary>
            InputKeyboard,
            /// <summary>
            /// Contains Hardware event data
            /// </summary>
            InputHardware
        }

        /// <summary>
        /// The flags that a MouseInput.dwFlags can contain
        /// </summary>
        [Flags]
        public enum SendInputMouseEventFlags : uint
        {
            /// <summary>
            /// Movement occured
            /// </summary>
            MOUSEEVENTF_MOVE = 0x0001,
            /// <summary>
            /// button down (pair with an up to create a full click)
            /// </summary>
            MOUSEEVENTF_LEFTDOWN = 0x0002,
            /// <summary>
            /// button up (pair with a down to create a full click)
            /// </summary>
            MOUSEEVENTF_LEFTUP = 0x0004,
            /// <summary>
            /// button down (pair with an up to create a full click)
            /// </summary>
            MOUSEEVENTF_RIGHTDOWN = 0x0008,
            /// <summary>
            /// button up (pair with a down to create a full click)
            /// </summary>
            MOUSEEVENTF_RIGHTUP = 0x0010,
            /// <summary>
            /// button down (pair with an up to create a full click)
            /// </summary>
            MOUSEEVENTF_MIDDLEDOWN = 0x0020,
            /// <summary>
            /// button up (pair with a down to create a full click)
            /// </summary>
            MOUSEEVENTF_MIDDLEUP = 0x0040,
            /// <summary>
            /// button down (pair with an up to create a full click)
            /// </summary>
            MOUSEEVENTF_XDOWN = 0x0080,
            /// <summary>
            /// button up (pair with a down to create a full click)
            /// </summary>
            MOUSEEVENTF_XUP = 0x0100,
            /// <summary>
            /// Wheel was moved, the value of mouseData is the number of movement values
            /// </summary>
            MOUSEEVENTF_WHEEL = 0x0800,
            /// <summary>
            /// Map X,Y to entire desktop, must be used with MOUSEEVENT_ABSOLUTE
            /// </summary>
            MOUSEEVENTF_VIRTUALDESK = 0x4000,
            /// <summary>
            /// The X and Y members contain normalised Absolute Co-Ords. If not set X and Y are relative
            /// data to the last position (i.e. change in position from last event)
            /// </summary>
            MOUSEEVENTF_ABSOLUTE = 0x8000
        }

        /// <summary>
        /// Contains information about a simulated mouse event.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct SendInputMouse
        {
            /// <summary>
            /// The absolute position of the mouse, or the amount of motion since the last mouse 
            /// event was generated, depending on the value of the dwFlags member. Absolute data is 
            /// specified as the x coordinate of the mouse; relative data is specified as the number 
            /// of pixels moved. 
            /// </summary>
            public int dx;
            /// <summary>
            /// The absolute position of the mouse, or the amount of motion since the last mouse 
            /// event was generated, depending on the value of the dwFlags member. Absolute data 
            /// is specified as the y coordinate of the mouse; relative data is specified as the 
            /// number of pixels moved. 
            /// </summary>
            public int dy;
            /// <summary>
            /// If dwFlags contains MOUSEEVENTF_WHEEL, then mouseData specifies the amount of wheel 
            /// movement. A positive value indicates that the wheel was rotated forward, away from the 
            /// user; a negative value indicates that the wheel was rotated backward, toward the user. 
            /// One wheel click is defined as WHEEL_DELTA, which is 120.
            /// 
            /// Windows Vista: If dwFlags contains MOUSEEVENTF_HWHEEL, then dwData specifies the 
            /// amount of wheel movement. A positive value indicates that the wheel was rotated to the 
            /// right; a negative value indicates that the wheel was rotated to the left. One wheel 
            /// click is defined as WHEEL_DELTA, which is 120.
            /// 
            /// If dwFlags does not contain MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or MOUSEEVENTF_XUP, 
            /// then mouseData should be zero.
            /// 
            /// If dwFlags contains MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP, then mouseData specifies which 
            /// X buttons were pressed or released. This value may be any combination of the following 
            /// flags. 
            /// </summary>
            public uint MouseData;
            /// <summary>
            /// A set of bit flags that specify various aspects of mouse motion and button clicks. 
            /// 
            /// The bit flags that specify mouse button status are set to indicate changes in status, not 
            /// ongoing conditions. For example, if the left mouse button is pressed and held down, 
            /// MOUSEEVENTF_LEFTDOWN is set when the left button is first pressed, but not for subsequent 
            /// motions. Similarly, MOUSEEVENTF_LEFTUP is set only when the button is first released.
            /// 
            /// You cannot specify both the MOUSEEVENTF_WHEEL flag and either MOUSEEVENTF_XDOWN or 
            /// MOUSEEVENTF_XUP flags simultaneously in the dwFlags parameter, because they both 
            /// require use of the mouseData field. 
            /// </summary>
            public SendInputMouseEventFlags Flags;
            /// <summary>
            /// The time stamp for the event, in milliseconds. If this parameter is 0, the system will 
            /// provide its own time stamp. 
            /// </summary>
            public uint Time;
            /// <summary>
            /// An additional value associated with the mouse event. An application calls 
            /// GetMessageExtraInfo to obtain this extra information. 
            /// </summary>
            public IntPtr ExtraInfo;
        }

        /// <summary>
        /// Specifies various aspects of a keystroke. 
        /// This member can be certain combinations of the following values. 
        /// </summary>
        [Flags]
        public enum SendInputKeyboardFlags : uint
        {
            /// <summary>
            /// If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224).
            /// </summary>
            KEYEVENTF_EXTENDEDKEY = 0x0001,
            /// <summary>
            /// If specified, the key is being released. If not specified, the key is being pressed.
            /// </summary>
            KEYEVENTF_KEYUP = 0x0002,
            /// <summary>
            /// If specified, the system synthesizes a VK_PACKET keystroke. The VirtualKey parameter 
            /// must be zero. This flag can only be combined with the KEYEVENTF_KEYUP flag. For 
            /// more information, see the Remarks section. 
            /// </summary>
            KEYEVENTF_UNICODE = 0x0004,
            /// <summary>
            /// If specified, ScanCode identifies the key and VirtualKey is ignored. 
            /// </summary>
            KEYEVENTF_SCANCODE = 0x0008
        }

        /// <summary>
        /// Contains information about a simulated keyboard event.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct SendInputKeyboard
        {
            /// <summary>
            /// A virtual-key code. The code must be a value in the range 1 to 254. If the dwFlags member 
            /// specifies KEYEVENTF_UNICODE, wVk must be 0. 
            /// </summary>
            public Keys VirtualKey;
            /// <summary>
            /// A hardware scan code for the key. If dwFlags specifies KEYEVENTF_UNICODE, wScan 
            /// specifies a Unicode character which is to be sent to the foreground application. 
            /// </summary>
            public ushort ScanCode;
            /// <summary>
            /// Specifies various aspects of a keystroke. This member can be certain combinations of 
            /// the following values. 
            /// </summary>
            public SendInputKeyboardFlags Flags;
            /// <summary>
            /// The time stamp for the event, in milliseconds. If this parameter is zero, the 
            /// system will provide its own time stamp. 
            /// </summary>
            public uint Time;
            /// <summary>
            /// An additional value associated with the keystroke. Use the GetMessageExtraInfo 
            /// function to obtain this information. 
            /// </summary>
            public IntPtr ExtraInfo;
        }

        /// <summary>
        /// Contains information about a simulated message generated by an input device 
        /// other than a keyboard or mouse. 
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct SendInputHardware
        {
            /// <summary>
            /// The message generated by the input hardware. 
            /// </summary>
            public uint Msg;
            /// <summary>
            /// The low-order word of the lParam parameter for uMsg. 
            /// </summary>
            public ushort ParamL;
            /// <summary>
            /// The high-order word of the lParam parameter for uMsg. 
            /// </summary>
            public ushort ParamH;
        }

        /// <summary>
        /// Used by SendInput to store information for synthesizing input events such as 
        /// keystrokes, mouse movement, and mouse clicks.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct SendInputData
        {
            /// <summary>
            /// The actual data type contained in the union Field
            /// </summary>
            public SendInputEventType Type;
            public Union Data;
            [StructLayout(LayoutKind.Explicit)]
            public struct Union
            {
                /// <summary>
                /// The Mouse Input Data
                /// </summary>
                [FieldOffset(0)]
                public SendInputMouse Mouse;
                /// <summary>
                /// The Keyboard input data
                /// </summary>
                [FieldOffset(0)]
                public SendInputKeyboard Keyboard;
                /// <summary>
                /// The hardware input data
                /// </summary>
                [FieldOffset(0)]
                public SendInputHardware Hardware;
            }
        }

        /// <summary>
        /// Synthesizes keystrokes, mouse motions, and button clicks.
        /// </summary>
        /// <param name="nInputs">
        /// The number of structures in the Inputs array.
        /// </param>
        /// <param name="Inputs">
        /// An array of SendInputData structures. Each structure represents an event to be 
        /// inserted into the keyboard or mouse input stream.
        /// </param>
        /// <param name="cbSize">
        /// The size, in bytes, of an SendInputData structure. If cbSize is not the size of an 
        /// INPUT structure, the function fails.
        /// </param>
        /// <returns>
        /// The function returns the number of events that it successfully inserted into 
        /// the keyboard or mouse input stream. If the function returns zero, the input 
        /// was already blocked by another thread. To get extended error information, call GetLastError.
        /// This function fails when it is blocked by UIPI. Note that neither GetLastError 
        /// nor the return value will indicate the failure was caused by UIPI blocking.
        /// </returns>
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern uint SendInput
        (
            uint nInputs,
            SendInputData[] Inputs,
            int cbSize
        );

        /// <summary>
        /// Retrieves a handle to the desktop window. The desktop window covers the 
        /// entire screen. The desktop window is the area on top of which other windows are painted. 
        /// </summary>
        /// <returns>
        /// The return value is a handle to the desktop window. 
        /// </returns>
        [DllImport("coredll.dll")]
        public static extern IntPtr GetDesktopWindow();

        /// <summary>
        /// Brings the thread that created the specified window into the foreground and activates 
        /// the window. Keyboard input is directed to the window, and various visual cues are 
        /// changed for the user. The system assigns a slightly higher priority to the thread 
        /// that created the foreground window than it does to other threads. 
        /// </summary>
        /// <param name="hWnd">
        /// A handle to the window that should be activated and brought to the foreground. 
        /// </param>
        /// <returns>
        /// If the window was brought to the foreground, the return value is nonzero.
        /// If the window was not brought to the foreground, the return value is zero.
        /// </returns>
        [DllImport("coredll.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
    }
}